package com.tzu.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 对象工具
 *
 * @author braveheartwzm
 */
public final class ObjectTools {

    /**
     * Pseudo URL prefix for loading from the class path: "classpath:"
     */
    public static final String URL_PROTOCOL_CLASSPATH = "classpath";

    /**
     * URL protocol for a file in the file system: "file"
     */
    public static final String URL_PROTOCOL_FILE = "file";

    /**
     * URL protocol for an entry from a jar file: "jar"
     */
    public static final String URL_PROTOCOL_JAR = "jar";

    /**
     * URL protocol for an entry from a war file: "war"
     */
    public static final String URL_PROTOCOL_WAR = "war";

    /**
     * URL protocol for an entry from a zip file: "zip"
     */
    public static final String URL_PROTOCOL_ZIP = "zip";

    /**
     * URL protocol for an entry from a WebSphere jar file: "wsjar"
     */
    public static final String URL_PROTOCOL_WSJAR = "wsjar";

    /**
     * URL protocol for an entry from a JBoss jar file: "vfszip"
     */
    public static final String URL_PROTOCOL_VFSZIP = "vfszip";

    /**
     * URL protocol for a JBoss file system resource: "vfsfile"
     */
    public static final String URL_PROTOCOL_VFSFILE = "vfsfile";

    /**
     * URL protocol for a general JBoss VFS resource: "vfs"
     */
    public static final String URL_PROTOCOL_VFS = "vfs";

    /**
     * File extension for a regular jar file: ".jar"
     */
    public static final String JAR_FILE_EXTENSION = ".jar";

    /**
     * Separator between JAR URL and file path within the JAR: "!/"
     */
    public static final String JAR_URL_SEPARATOR = "!/";

    /**
     * Special separator between WAR URL and jar part on Tomcat
     */
    public static final String WAR_URL_SEPARATOR = "*/";


    private static final String _class = ".class";
    private static final String classes = "classes";

    private ObjectTools() {
    }

    /**
     * 深度复制对象<br>
     * 被复制的对象必须实现 <code>java.io.Serializable</code> 接口
     *
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Object deepClone(Object obj) throws IOException,
            ClassNotFoundException {
        /* 写入当前对象的二进制流 */
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);

        /* 读出二进制流产生的新对象 */
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }

    /**
     * 快速复制数组，将根据数组index的位置进行替换性复制
     */
    public static <A> void copyArray(A[] from, A[] tag) {
        System.arraycopy(from, 0, tag, 0, from.length);
    }

    /**
     * map对象提取list对象
     */
    public static <T> List<T> mapGetList(Map<String, T> map) {
        return new ArrayList<T>(map.values());
    }

    /**
     * map按照key进行迭代输出list
     */
    public static <T> List<T> mapGetListOrderByKey(Map<String, T> map) {
        List<T> list = new ArrayList<T>(map.size());
        Iterator<String> iters = map.keySet().iterator();
        while (iters.hasNext()) {
            list.add(map.get(iters.next()));
        }
        return list;
    }

    /**
     * 序列化对象
     *
     * @param obj 可序列的对象
     */
    public static byte[] serialize(Serializable obj) {
        try {
            ObjectOutputStream oos = null;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存序列化对象到文件
     *
     * @param obj  可序列对象
     * @param path 保存路径
     */
    public static boolean serialize(Serializable obj, String path) {
        File file = new File(path);
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(
                    new FileOutputStream(file));
            outputStream.writeObject(obj);
            outputStream.flush();
            outputStream.close();
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 反序列化对象
     */
    public static <T> T deserialize(byte[] bytes) {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
            return (T) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                ois.close();
            } catch (IOException e) {
            }
        }
        return null;
    }

    /**
     * 从文件读取序列化对象
     *
     * @param path 文件路径
     */
    @SuppressWarnings("unchecked")
    public static <T> T deserialize(String path) {
        File file = new File(path);
        if (!file.exists()) {
            System.err.println("反序列化文件不存在：" + path);
            return null;
        }
        ObjectInputStream inputStream = null;
        try {
            inputStream = new ObjectInputStream(new FileInputStream(file));
            return (T) inputStream.readObject();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
            }
        }
        return null;
    }


    //==============================

    /**
     * 根据路径获取URL对象
     */
    private static Enumeration<URL> getResources(String path) throws IOException {
        Enumeration<URL> urls = ClassLoader.getSystemResources(path);
        if (null == urls) {
            urls = Thread.currentThread().getContextClassLoader().getResources(path);
        }
        return urls;
    }


    /**
     * 扫码jar包或者目录下的class
     */
    public static List<String> scanPackageClass(String basePackage) throws IOException {
        String pkgname = basePackage.replace(".", "/") + "/";
//		URL url = Thread.currentThread().getContextClassLoader().getResource(pkgname);
//        URL url = ClassLoader.getSystemResource(pkgname);
        Enumeration<URL> urls = getResources(pkgname);
        //使用treeset收集class
        Set<String> classlist = new TreeSet<>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            if (null == url) {
                return null;
            }
            //获取协议
            String protocol = url.getProtocol();
            if (URL_PROTOCOL_FILE.equals(protocol)) {
                String file = url.getFile();
                List<File> flist = FileTools.getAllFiles(new File(file));
                for (File fc : flist) {
                    String path = fc.getPath();
                    path = path.substring(path.indexOf(classes) + classes.length() + 1, path.length() - _class.length());
                    classlist.add(path.replace(File.separator, "."));
                }
            } else if (URL_PROTOCOL_JAR.equals(protocol)) {
                try {
                    JarURLConnection connection = (JarURLConnection) url.openConnection();
                    JarFile jarFile = connection.getJarFile();
                    Enumeration<JarEntry> jarEntries = jarFile.entries();
                    while (jarEntries.hasMoreElements()) {
                        JarEntry entry = jarEntries.nextElement();
                        String name = entry.getName();
                        if (name.startsWith(pkgname)) {
                            int tail = name.indexOf(_class);
                            if (tail > 0) {
 //                               System.out.println(name);
                                name = name.substring(0, tail);
                                classlist.add(name.replace("/", "."));
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                throw new IOException("未对该协议进行处理：" + protocol);
            }
        }
        return new ArrayList<>(classlist);
    }


    //=================================================================================================
    public static void main(String[] args) throws IOException {

        String basePackage = "org.springframework.core";

        System.out.println("=======================================");
        List<String> slist = scanPackageClass(basePackage);
        System.out.println(slist);
        System.out.println(slist.size());

        List<String> list = scanPackageClass(basePackage);
		System.out.println(list);
        System.out.println(list.size());

    }

}
